﻿/*
 * mdc.cpp
 *
 *  Created on: 2020年5月3日
 *      Author: root
 */
//---------------------------------------------------------------------------

#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/ioctl.h>

#include "mdc.h"
#include "log.h"
//---------------------------------------------------------------------------

#define MAX_NZL	64							//最大枪数

static int NZLCNT = 0;						//实际枪数
static TNZLOILDATA NzlDat[MAX_NZL];			//枪信息
static bool ReadWatch = false;				//socket monitor
//---------------------------------------------------------------------------

TMDC::TMDC(int ANo) : MDCNo(ANo), Working(false), Port(0)
{
	CltSock = NULL;
	SndThread = NULL;
	RcvThread = NULL;
	ErrCallback = NULL;
	NotifyEvent = NULL;

	memset(IP, 0, 20);
	CmdLst.clear();
	MDC_CFG.Init();

	NZLCNT = 0;
	memset(NzlDat, 0, sizeof(TNZLOILDATA) * MAX_NZL);
}
//---------------------------------------------------------------------------

TMDC::~TMDC()
{
	StopWork();
}
//---------------------------------------------------------------------------

int TMDC::GetMDCNo()
{
	return MDCNo;
}
//---------------------------------------------------------------------------

//初始化集线器IP、端口
int TMDC::Init(char *pzIPv4, uint16 uPort)
{
	if(!IsIPv4(pzIPv4)) return 1;	//无效IP
	if(uPort > 65634) return 2;		//无效端口
	strcpy(IP, pzIPv4);
	Port = uPort;
	return 0;
}
//---------------------------------------------------------------------------

//连接集线器
// 0: 成功, -1: 失败
int TMDC::Connect()
{
	int r = CltSock->CreateSocket();
	//0: 成功, 1: 已创建, -1: 失败
	if (r >= 0)
	{   //0:成功, -1:失败
		r = CltSock->ConnectTo(IP, Port);
	}
	return r;
}
//---------------------------------------------------------------------------

//释放命令队列空间
void TMDC::FreeCmdLst()
{
	TSNDCMDLST tmpLst;
	tmpLst.swap(CmdLst);
	int cnt = tmpLst.size();
	for(int i=0; i<cnt; i++)
	{
		TFRAMEBIN *pfrm = tmpLst.at(i);
		delete pfrm;
	}
	tmpLst.clear();
}
//---------------------------------------------------------------------------

//读取Config信息
void TMDC::GetConfigInfo()
{
	TFRAMEBIN *pfrm = new TFRAMEBIN();
	TFRAMEBIN &pak = *pfrm;
	pak.Init();
	pak.HDR = FRMHDR;
	pak.Cmd = 0x11;
	pak.DataSize = 0;
	pak.CRC = CalcCRC16(&pak.Cmd, 3);
	pak.TAIL = FRMTAIL;

	CmdLst.push_back(pfrm);
}
//---------------------------------------------------------------------------

//读指定枪价格
void TMDC::GetNzlPrc(BYTE chl, BYTE nzl)
{
	TFRAMEBIN *pfrm = new TFRAMEBIN();
	TFRAMEBIN &pak = *pfrm;
	pak.Init();
	pak.HDR = FRMHDR;
	pak.Cmd = 0x27;								//读取枪的实时价格
	pak.DataSize = 2;							//数据长度
	pak.Data[0] = chl;
	pak.Data[1] = nzl;
	pak.CRC = CalcCRC16(&pak.Cmd, 5);			//CRC
	pak.TAIL = FRMTAIL;							//TAIL

	CmdLst.push_back(pfrm);
}
//---------------------------------------------------------------------------

//设置指定枪价格
void TMDC::SetNzlPrc(BYTE chl, BYTE nzl, uint16 prc)
{
	TFRAMEBIN *pfrm = new TFRAMEBIN();
	TFRAMEBIN &pak = *pfrm;
	pak.Init();
	pak.HDR = FRMHDR;
	pak.Cmd = 0x26;								//设置枪的实时价格
	pak.DataSize = 6;							//数据长度
	pak.Data[0] = chl;
	pak.Data[1] = nzl;
	uint16 *px = (uint16*)(&pak.Data[2]);
	*px = prc;									//Price
	pak.CRC = CalcCRC16(&pak.Cmd, 9);			//CRC
	pak.TAIL = FRMTAIL;							//TAIL

	CmdLst.push_back(pfrm);
}
//---------------------------------------------------------------------------

//读所有枪价格信息
void TMDC::GetNzlsPrc()
{
	for(int i=0; i<NZLCNT; i++)
	{
		TNZLOILDATA &r = NzlDat[i];
		GetNzlPrc(r.ChlNo, r.NZL);
	}
}
//---------------------------------------------------------------------------

//启动集线器工作线程
//0: 成功, 1: 已启动, -1: 失败
int TMDC::StartWork()
{
	if(!Working)
	{
		CltSock = new TClientSocket(this);
		if(CltSock)
		{
			int r = Connect();
			if(r == 0)
			{
				Working = true;
				SndThread = new TSendThread(this);
				RcvThread = new TRecvThread(this);

				FreeCmdLst();
				GetConfigInfo();		//读取Config信息
			}
			return r;                   // 0 or -1
		}
		return -1;  					//创建对象失败
	}
	return 1;							//已启动
}
//---------------------------------------------------------------------------

int TMDC::StopWork()
{
	if(Working)
	{
		Working = false;
		CltSock->CloseSocket();

		while(!SndThread->IsOver) SleepEx(20);
		delete SndThread;
		SndThread = NULL;

		while(!RcvThread->IsOver) SleepEx(20);
		delete RcvThread;
		RcvThread = NULL;

		delete CltSock;
		CltSock = NULL;
	}
	return 0;
}
//---------------------------------------------------------------------------

int TMDC::DoCommand(int cmd, BYTE *pData, uint32 uSize)
{
	int iRet = 0;
	switch(cmd)
	{
		case 201: //查MDC系统时间;
		QryMDCTime();
		break;

		case 202: //设MDC系统时间，pData指向数据结构TDATETIME(日期时间)，uSize为其长度;
		{
			TDATETIME *pDT = (TDATETIME *)(pData);
			SetMDCTime(pDT);
		}
		break;

		case 203: //查枪油品信息，pData指向TNZLADDR结构数据，uSize为其长度；
		{
			TNZLADDR *pIf = (TNZLADDR *)pData;
			int m = uSize / sizeof(TNZLADDR);
			for(int i=0; i<m; i++)
			{
				QryNZLOilInfo(pIf++);
			}
		}
		break;

		case 204: //设置枪油品信息，pData指向TNZLOILINFO结构数据，uSize为其长度；
		{
			TNZLOILINFO *pIf = (TNZLOILINFO *)pData;
			int m = uSize / sizeof(TNZLOILINFO);
			for(int i=0; i<m; i++)
			{
				SetNZLOilInfo(pIf++);
			}
		}
		break;

		case 205: //查枪泵码信息，pData指向TNZLADDR结构数据，uSize为其长度；
		{
			TNZLADDR *pIf = (TNZLADDR *)pData;
			int m = uSize / sizeof(TNZLADDR);
			for(int i=0; i<m; i++)
			{
				QryVTOT(pIf++);
			}
		}
		break;

		case 206: //查指定TTC交易，pData为指向TMDCTTC的结构，uSize为其长度；
		{
			TMDCTTC *pIf = (TMDCTTC *)pData;
			int m = uSize / sizeof(TMDCTTC);
			for(int i=0; i<m; i++)
			{
				QryTTC(pIf++);
			}
		}
		break;

		case 207:
		GetMaxTTC(pData, uSize);
		break;

		case 208: //设置上位机授权时段，最多三个时段，pData为指向的结构，uSize为其长度
		SetAuthCfg(pData, uSize);
		break;

		case 209: //查上位机授权时段，pData: 无效,可为NULL，uSize: 无效，可为0;
		GetAuthCfg();
		break;

		case 210: //给指枪授权开机加油，pData指向TNZLADDR结构数据，uSize为其长度（字节数），可授权1个或多个；枪在加油中或离线状态不能授权；
		GunAuth(pData, uSize);
		break;

		case 211: //取消授权，pData指向TNZLADDR结构数据，uSize为其长度（字节数），可取消授权1个或多个；
		GunCancelAuth(pData, uSize);
		break;

		case 212: //查集线器硬件信息;
		QryDevInfo();
		break;

		default:
		{
			iRet = 1;
			char sErr[80] = { 0 };
			snprintf(sErr, 80, "Error: DoCommand: Unknown command: %d.", cmd);
			LogOut(sErr);
		}
		break;
	}

	return iRet;
}
//---------------------------------------------------------------------------

//查MDC产品SN,出厂日期等硬件信息
void TMDC::QryDevInfo()
{
	TFRAMEBIN *frm = new TFRAMEBIN();
	TFRAMEBIN &pak = *frm;
	pak.Init();
	pak.HDR = FRMHDR;
	pak.Cmd = 0x13;									//查MDC产品SN,出厂日期等硬件信息
	pak.DataSize = 0;                   			//数据长度0
	pak.CRC = CalcCRC16(&pak.Cmd, 3);   			//CRC
	pak.TAIL = FRMTAIL;                 			//TAIL

	CmdLst.push_back(frm);
}
//---------------------------------------------------------------------------

//查MDC系统时间
void TMDC::QryMDCTime()
{
	TFRAMEBIN *frm = new TFRAMEBIN();
	TFRAMEBIN &pak = *frm;
	pak.Init();
	pak.HDR = FRMHDR;
	pak.Cmd = 0x19;									//读取FCC时间
	pak.DataSize = 0;                   			//数据长度0
	pak.CRC = CalcCRC16(&pak.Cmd, 3);   			//CRC
	pak.TAIL = FRMTAIL;                 			//TAIL

	CmdLst.push_back(frm);
}
//---------------------------------------------------------------------------

//设MDC系统时间
void TMDC::SetMDCTime(TDATETIME *pdt)
{
	TDATETIME &dt = *pdt;
	uint16 year = dt.Year;
	BYTE Month = dt.Month;
	BYTE Day = dt.Day;
	BYTE Hour = dt.Hour;
	BYTE Min = dt.Min;
	BYTE Sec = dt.Sec;

	TFRAMEBIN *frm = new TFRAMEBIN();
	TFRAMEBIN &pak = *frm;
	pak.Init();
	pak.HDR = FRMHDR;
	pak.Cmd = 0x18;									//设置FCC时间
	pak.DataSize = 8;                   			//数据长度
	year = WordToCBCD(year);
	pak.Data[0] = year & 0xFF; 						//低字节先发送
	pak.Data[1] = (year >> 8) & 0xFF;				//高字节后发送
	pak.Data[2] = ByteToCBCD(Month);
	pak.Data[3] = ByteToCBCD(Day);
	pak.Data[4] = ByteToCBCD(Hour);
	pak.Data[5] = ByteToCBCD(Min);
	pak.Data[6] = ByteToCBCD(Sec);
	pak.Data[7] = ByteToCBCD(1);					//星期暂时无用
	pak.CRC = CalcCRC16(&pak.Cmd, 11);  			//CRC
	pak.TAIL = FRMTAIL;                 			//TAIL

	CmdLst.push_back(frm);
}
//---------------------------------------------------------------------------

void TMDC::QryNzlPrc(TNZLADDR *pDat)
{
	TFRAMEBIN *frm = new TFRAMEBIN();
	TFRAMEBIN &pak = *frm;
	pak.Init();
	pak.HDR = FRMHDR;
	pak.Cmd = 0x27;									//查枪油品价格
	pak.DataSize = 2;                   			//数据长度
	pak.Data[0] = pDat->ChlNo; 						//低字节先发送
	pak.Data[1] = pDat->NZL;						//高字节后发送
	pak.CRC = CalcCRC16(&pak.Cmd, 5);  				//CRC
	pak.TAIL = FRMTAIL;                 			//TAIL

	CmdLst.push_back(frm);
}
//---------------------------------------------------------------------------

//查枪油品信息
void TMDC::QryNZLOilInfo(TNZLADDR *pDat)
{
	QryNzlPrc(pDat);
//	TNZLADDR &adr = *pDat;
//	BYTE chn = adr.ChlNo;
//	BYTE nzl = adr.NZL;
//	TNZLOILINFO ifo = GetNZLInfoFromCFG(chn, nzl);
//	QryNzlPrc(&adr);
//
//	if(NotifyEvent) NotifyEvent(MDCNo, 105, (BYTE*)&ifo, sizeof(TNZLOILINFO));
}
//---------------------------------------------------------------------------

//更新配置
void TMDC::UpCFG(BYTE chn, BYTE nzl, uint16 OilCode)
{
	bool bFind = false;
	int m = MDC_CFG.Count;
	for(int i=0; i<m; i++)
	{
		TCHLINFO &chl = MDC_CFG.Chls[i];
		if(chl.ChannelNo == chn)
		{
			int n = chl.NZN_Count;
			for(int j=0; j<n; j++)
			{
				TNZN &gun = chl.Guns[j];
				if(gun.GunCode == nzl)
				{
					gun.OilCode = OilCode;
					bFind = true;
					break;
				}
			}
		}
		if(bFind) break;
	}

	if(!bFind) return;

	TFRAMEBIN *pfrm = new TFRAMEBIN();
	TFRAMEBIN &pak = *pfrm;
	pak.Init();
	pak.HDR = FRMHDR;
	pak.Cmd = 0x10;

	int x = 0;
	BYTE *p = pak.Data;
	p[x++] = (MDC_CFG.IP & 0xFF);
	p[x++] = ((MDC_CFG.IP >>  8) & 0xFF);
	p[x++] = ((MDC_CFG.IP >> 16) & 0xFF);
	p[x++] = ((MDC_CFG.IP >> 24) & 0xFF);
	p[x++] = (MDC_CFG.Port & 0xFF);
	p[x++] = ((MDC_CFG.Port >> 8) & 0xFF);
	p[x++] = MDC_CFG.PC_Log;
	p[x++] = MDC_CFG.Count;

	for(int i=0; i<m; i++)
	{
		TCHLINFO &chl = MDC_CFG.Chls[i];
		TSERIALPARAM &pm = chl.Param;
		p[x++] = chl.ChannelNo;
		p[x++] = chl.Protocol;
		BYTE *r = (BYTE*)&pm.BaudRate;
		p[x++] = r[0];
		p[x++] = r[1];
		p[x++] = r[2];
		p[x++] = r[3];
		p[x++] = pm.ByteSize;
		p[x++] = pm.Parity;
		p[x++] = pm.StopBits;
		p[x++] = chl.AutoAuthorize;
		p[x++] = chl.Pump_Log;
		p[x++] = chl.NZN_Count;

		for(BYTE j=0; j<chl.NZN_Count; j++)
		{
			TNZN &gun = chl.Guns[j];
			p[x++] = gun.GunCode;
			p[x++] = (gun.OilCode & 0xFF);
			p[x++] = ((gun.OilCode >> 8) & 0xFF);
		}
	}

	pak.DataSize = x;
	pak.CRC = CalcCRC16(&pak.Cmd, x + 3);
	pak.TAIL = FRMTAIL;

	CmdLst.push_back(pfrm);
}
//---------------------------------------------------------------------------

//设置枪油品信息
void TMDC::SetNZLOilInfo(TNZLOILINFO *pDat)
{
	TNZLOILINFO &rc = *pDat;
	for(int i=0; i<NZLCNT; i++)
	{
		TNZLOILDATA &rd = NzlDat[i];
		if((rd.ChlNo == rc.ChlNo) && (rd.NZL == rc.NZL))
		{
			rd.Oil2.OilCode = rc.OilCode;
			rd.Oil2.Price = rc.Price;
			rd.Oil2.Density = rc.Density;
			rd.Oil1.Density = rc.Density;

			if(rd.Oil1.OilCode != rd.Oil2.OilCode)
			{
				UpCFG(rd.ChlNo, rd.NZL, rc.OilCode);
				rd.Oil1.OilCode = rd.Oil2.OilCode;
			}

			SetNzlPrc(rc.ChlNo, rc.NZL, rc.Price);
			break;
		}
	}
}
//---------------------------------------------------------------------------

//查枪泵码信息
void TMDC::QryVTOT(TNZLADDR *pDat)
{
	TFRAMEBIN *frm = new TFRAMEBIN();
	TFRAMEBIN &pak = *frm;
	pak.Init();
	pak.HDR = FRMHDR;
	pak.Cmd = 0x25;									//读取泵码命令
	pak.DataSize = 2;                   			//数据长度
	pak.Data[0] = pDat->ChlNo;
	pak.Data[1] = pDat->NZL;
	pak.CRC = CalcCRC16(&pak.Cmd, 5);   			//CRC
	pak.TAIL = FRMTAIL;                 			//TAIL

	CmdLst.push_back(frm);
}
//---------------------------------------------------------------------------

//查指定TTC交易
void TMDC::QryTTC(TMDCTTC *pDat)
{
	TFRAMEBIN *frm = new TFRAMEBIN();
	TFRAMEBIN &pak = *frm;
	pak.Init();
	pak.HDR = FRMHDR;
	pak.Cmd = 0x16;									//读取指定历史交易
	pak.DataSize = 6;                				//数据长度
	BYTE *p = pak.Data;
	*p++ = 0;										//type: 0: MDC TTC, 1:Pump TTC
	*p++ = pDat->ChlNo;								//通道
	uint32 *pttc = (uint32*)p;
	*pttc = pDat->TTC;								//MDC TTC
	pak.CRC = CalcCRC16(&pak.Cmd, 9);  				//CRC
	pak.TAIL = FRMTAIL;                 			//TAIL

	CmdLst.push_back(frm);
}
//---------------------------------------------------------------------------

//Get a channel max FCC_TTC value
void TMDC::GetMaxTTC(BYTE *pData, uint32 uSize)
{
	TFRAMEBIN *frm = new TFRAMEBIN();
	TFRAMEBIN &pak = *frm;
	pak.Init();
	pak.HDR = FRMHDR;
	pak.Cmd = 0x20;									//读取通道 Max FCC TTC
	pak.DataSize = 1;                				//数据长度
	pak.Data[0] = pData[0];							//通道
	pak.CRC = CalcCRC16(&pak.Cmd, 4);  				//CRC
	pak.TAIL = FRMTAIL;                 			//TAIL

	CmdLst.push_back(frm);
}
//---------------------------------------------------------------------------

// Set MDC config file auth.conf contents.
void TMDC::SetAuthCfg(BYTE *pData, uint32 uSize)
{
	TFRAMEBIN *frm = new TFRAMEBIN();
	TAUTHCFG *pCfg = (TAUTHCFG *)pData;
	TFRAMEBIN &pak = *frm;
	pak.Init();
	pak.HDR = FRMHDR;
	pak.Cmd = 0x36;									//cmd
	pak.DataSize = 19;                				//数据长度
	BYTE *p = pak.Data;
	int m = pCfg->Num;
	*p++ = (BYTE)m;
	for(int i=0; i<m; i++)
	{
		TPICETIME &t = pCfg->Items[i];
		*p++ = t.tm0.Hour;
		*p++ = t.tm0.Min;
		*p++ = t.tm0.Sec;
		*p++ = t.tm1.Hour;
		*p++ = t.tm1.Min;
		*p++ = t.tm1.Sec;
	}

	pak.CRC = CalcCRC16(&pak.Cmd, 22);				//CRC
	pak.TAIL = FRMTAIL;                 			//TAIL

	CmdLst.push_back(frm);
}
//---------------------------------------------------------------------------

//Read MDC config file auth.conf contents.
void TMDC::GetAuthCfg()
{
	TFRAMEBIN *frm = new TFRAMEBIN();
	TFRAMEBIN &pak = *frm;
	pak.Init();
	pak.HDR = FRMHDR;
	pak.Cmd = 0x37;									//cmd
	pak.DataSize = 0;                				//数据长度
	pak.CRC = CalcCRC16(&pak.Cmd, 3);  				//CRC
	pak.TAIL = FRMTAIL;                 			//TAIL

	CmdLst.push_back(frm);
}
//---------------------------------------------------------------------------

//authorize for the nzl
void TMDC::GunAuth(BYTE *pData, uint32 uSize)
{
	TFRAMEBIN *frm = new TFRAMEBIN();
	TNZLADDR *pAddr = (TNZLADDR *)pData;
	TFRAMEBIN &pak = *frm;
	pak.Init();
	pak.HDR = FRMHDR;
	pak.Cmd = 0x23;									//授权(开机)
	pak.DataSize = 2;								//数据长度
	BYTE *p = pak.Data;
	p[0] = pAddr->ChlNo;
	p[1] = pAddr->NZL;
	pak.CRC = CalcCRC16(&pak.Cmd, pak.DataSize + 3);//CRC
	pak.TAIL = FRMTAIL;                 			//TAIL

	CmdLst.push_back(frm);
}
//---------------------------------------------------------------------------

//Cancel authorize for the nzl
void TMDC::GunCancelAuth(BYTE *pData, uint32 uSize)
{
	TFRAMEBIN *frm = new TFRAMEBIN();
	TNZLADDR *pAddr = (TNZLADDR *)pData;
	TFRAMEBIN &pak = *frm;
	pak.Init();
	pak.HDR = FRMHDR;
	pak.Cmd = 0x24;									//取消授权(关机)
	pak.DataSize = sizeof(TNZLADDR);				//数据长度
	BYTE *p = pak.Data;
	p[0] = pAddr->ChlNo;
	p[1] = pAddr->NZL;
	pak.CRC = CalcCRC16(&pak.Cmd, pak.DataSize + 3);//CRC
	pak.TAIL = FRMTAIL;                 			//TAIL

	CmdLst.push_back(frm);
}
//---------------------------------------------------------------------------

void TMDC::SendCmd(TFRAMEBIN *frm)
{
	int len = (frm->DataSize + 6) * 2;
	TAutoMem M1(len);
	BYTE *pBuf = M1.GetBuffer();
	if(!EncodeFrame(frm, pBuf, len))
	{
		LogOut("EncodeFrame error.");
		return;
	}

	int s = CltSock->SendBuffer((char*)pBuf, len);
	if(s < 0)
	{
		CltSock->CloseSocket();
		SleepEx(500);
		Connect();
	}
	else if(s > 0)
	{
		if(NotifyEvent) NotifyEvent(MDCNo, 107, pBuf, len);
	}
}
//---------------------------------------------------------------------------

void TMDC::ReadFrame()
{
	TAutoMem M1(MAXASCSIZE + 20);
	TAutoMem M2(FRAMEBINSIZE + 20);
	BYTE *pBuf1 = M1.GetBuffer();
	BYTE *pBuf2 = M2.GetBuffer();
	if(!pBuf1 || !pBuf2)
	{
		LogOut("Error: ReadFrame() Out of memory.");
		return;
	}

	TFRAMEBIN *frm = (TFRAMEBIN *)pBuf2;

	int r = CltSock->RecvBuffer((char*)pBuf1, MAXASCSIZE);
	if(r < 0)
	{
		CltSock->CloseSocket();
		SleepEx(500);
		Connect();
	}
	else if(r > 0)
	{
		ReadWatch = true;
		if(NotifyEvent) NotifyEvent(MDCNo, 108, (BYTE*)pBuf1, r);
		if(DecodeFrame(frm, pBuf1, r)) ProcessFrame(frm);
	}
}
//---------------------------------------------------------------------------

//处理从MDC收到的数据帧,解析所有命令
void TMDC::ProcessFrame(TFRAMEBIN *pfrm)
{
	TFRAMEBIN &frm = *pfrm;
	int cmd = frm.Cmd;
	switch(cmd)
	{
		case 0x11:	//读取MDC配置信息的回复
		UL_MDCCFG(frm.Data);
		break;

		case 0x13:	//读取MDC版本信息的回复
		UL_DevInfo(frm.Data);
		break;

		case 0x19:	//获取MDC时间的回复
		UL_MDCTime(frm.Data);
		break;

		case 0x60:	//MDC上传交易数据
		UL_Transaction(frm.Data);
		break;

		case 0x61: 	//MDC回复TTC不存在
		UL_NoTTC(frm.Data);
		break;

		case 0x62:	//MDC上传油机状态
		UL_PumpState(frm.Data);
		break;

		case 0x65:	//MDC上传油枪总累计量
		UL_VTOT(frm.Data);
		break;

		case 0x67: 	//MDC上传油机实时价格信息
		UL_PumpPRC(frm.Data);
		break;

		case 0x20:	//FCC上传通道最大FCC_TTC
		UL_ChlMaxTTC(frm.Data);
		break;

		case 0x35:
		//UL_MDCSta();
		break;

		case 0x18: // Set pump time wait process
		case 0x27: // get pump price wait process
		break;

		case 0x22: //向上位机查询授权
		UL_QryAuth(frm.Data);
		break;

		case 0x23: //返回授权结果
		UL_AuthRet(frm.Data);
		break;

		case 0x24: //返回取消授权结果
		UL_CancelAuthRet(frm.Data);
		break;

		case 0x37: //查上位机授权时段返回结果
		UL_QryAuthCfg(frm.Data);
		break;

		case 0x38:
		UL_DevInfo(frm.Data);
		break;

		default:
		{
			char buf[80] = { 0 };
			snprintf(buf, 80, "Unknown command: %d.", cmd);
			LogOut(buf);
		}
	}
}
//---------------------------------------------------------------------------

//从枪配置信息中取枪信息
TNZLOILINFO TMDC::GetNZLInfoFromCFG(BYTE chn, BYTE nzl)
{
	TNZLOILINFO ifo;
	ifo.init();
	ifo.ChlNo = chn;
	ifo.NZL = nzl;

	for(int i=0; i<NZLCNT; i++)
	{
		TNZLOILDATA &r = NzlDat[i];
		if(r.ChlNo == chn && r.NZL == nzl)
		{
			ifo.OilCode = r.Oil1.OilCode;
			ifo.Price = r.Oil1.Price;
			ifo.Density = r.Oil1.Density;
			break;
		}
	}

	return ifo;
}
//---------------------------------------------------------------------------

//上传MDC配置信息
void TMDC::UL_MDCCFG(BYTE *pData)
{
	NZLCNT = 0;
	memset(NzlDat, 0, sizeof(TNZLOILDATA));

	BYTE *p = pData;
	MDC_CFG.Init();
	MDC_CFG.IP = *((uint32*)p);
	p += sizeof(uint32);
	MDC_CFG.Port = *((uint16*)p);
	p += sizeof(uint16);
	MDC_CFG.PC_Log = *p++;
	MDC_CFG.Count = *p++;

	TCHLINFO *pd = MDC_CFG.Chls;
	for (int i=0; i<MDC_CFG.Count; i++)
	{
		TCHLINFO &chl = pd[i];
		TCHLINFO *ps = (TCHLINFO*)p;
		chl = *ps;
		p += sizeof(TCHLINFO);
		p -= MAX_CHL_NZN * sizeof(TNZN);
		p += chl.NZN_Count * 3;

		for(int j=0; j<chl.NZN_Count; j++)
		{
			TNZN &nzl = chl.Guns[j];
			TNZLOILDATA &zdt = NzlDat[NZLCNT++];
			zdt.init();
			zdt.ChlNo = chl.ChannelNo;
			zdt.NZL = nzl.GunCode;
			zdt.Oil1.OilCode = nzl.OilCode;
			zdt.Oil2.OilCode = nzl.OilCode;
		}
	}

	//读配置信息后读一次枪价格信息
	GetNzlsPrc();
}
//---------------------------------------------------------------------------

//上传MDC系统时间信息
void TMDC::UL_MDCTime(BYTE *pData)
{
	BYTE *p = pData;
	TDATETIME dt;
	dt.Year = CBCDToWord(*((uint16*)p));
	p += sizeof(uint16);
	dt.Month = CBCDToByte(*p++);
	dt.Day = CBCDToByte(*p++);
	dt.Hour = CBCDToByte(*p++);
	dt.Min = CBCDToByte(*p++);
	dt.Sec = CBCDToByte(*p++);

	if(NotifyEvent) NotifyEvent(MDCNo, 104, (BYTE*)&dt, sizeof(TDATETIME));
}
//---------------------------------------------------------------------------

//上传交易信息
void TMDC::UL_Transaction(BYTE *pData)
{
	TRANSACTON rs;
	rs.init();

	BYTE *p = pData;
	rs.MDCTTC = *((uint32*)p);			//MDC TTC: 1-0xFFFFFFFF
	p += sizeof(uint32);
	rs.PumpTTC = *((uint32*)p); 		//Pump TTC: 1-0xFFFFFFFF
	p += sizeof(uint32);
	rs.ChlNo = *p++;					//通道号: 1-16
	rs.NZL = *p++;						//枪号: 1-254
	rs.OilCode = *((uint16*)p);			//油品: 中石化标准编码
	p += sizeof(uint16);
	rs.Price = *((uint16*)p);			//挂牌价（分）
	p += sizeof(uint16);
	rs.VOL = *((uint32*)p);				//升数（0.01升）
	p += sizeof(uint32);
	rs.Money = *((uint32*)p);			//金额（分）
	p += sizeof(uint32);
	rs.VTOT0 = *((uint32*)p);			//交易起泵码
	p += sizeof(uint32);
	rs.VTOT1 = *((uint32*)p);			//交易止泵码
	p += sizeof(uint32);
	
	rs.Year = *((uint16*)p);			//(交易时间)年
	p += sizeof(uint16);
	rs.Month = *p++;					//月: 1-12
	rs.Day = *p++;						//日: 1-31
	rs.Hour = *p++;						//时: 0-23
	rs.Min = *p++;						//分: 0-59
	rs.Sec = *p++;						//秒: 0-59

	rs.CardType = *p++;
	if(rs.CardType != 0) memcpy(rs.CardNo, p, 21);

	if(NotifyEvent) NotifyEvent(MDCNo, 103, (BYTE*)&rs, sizeof(TRANSACTON));
}
//---------------------------------------------------------------------------

//上传MDC通道TTC不存在
void TMDC::UL_NoTTC(BYTE *pData)
{
	TMDCTTC ttc;
	ttc.init();
	BYTE *p = pData;
	p++;
	ttc.ChlNo = *p++;
	ttc.TTC = *((uint32*)p);

	if(NotifyEvent) NotifyEvent(MDCNo, 109, (BYTE*)&ttc, sizeof(TMDCTTC));
}
//---------------------------------------------------------------------------

//上传油机状态信息
void TMDC::UL_PumpState(BYTE *pData)
{
	TNZLSTATUS NzlSta;
	NzlSta.init();
	BYTE *p = pData;

	NzlSta.ChlNo = *p++;
	NzlSta.NZL = *p++;

	uint8_t sta = ((*p++ >> 2) & 0x07);
	switch(sta)
	{
		case 0: //0未知/离线
		NzlSta.Status = 5;
		break;

		case 1: //1空闲
		case 4: //4加油中停机
		case 5: //5加油结束等取交易
		NzlSta.Status = 1;
		break;

		case 2: //2抬枪
		NzlSta.Status = 3;
		break;

		case 3: //3加油中
		{
			NzlSta.Status = 3;
			NzlSta.VOL = *((uint32*)p);
			p += sizeof(uint32);
			NzlSta.Money = *((uint32*)p);
		}
		break;
	}

	if(NotifyEvent) NotifyEvent(MDCNo, 102, (BYTE*)&NzlSta, sizeof(TNZLSTATUS));
}
//---------------------------------------------------------------------------

//上传油机泵码信息
void TMDC::UL_VTOT(BYTE *pData)
{
	TNZLVTOT vt;
	vt.init();
	BYTE *p = pData;

	vt.ChlNo = *p++;
	vt.NZL = *p++;
	vt.VTOT = *((uint32*)p);

	if(NotifyEvent) NotifyEvent(MDCNo, 106, (BYTE*)&vt, sizeof(TNZLVTOT));
}
//---------------------------------------------------------------------------

//上传油机价格信息
void TMDC::UL_PumpPRC(BYTE *pData)
{
	BYTE *p = pData;
	BYTE chn = *p++;						// 通道号
	BYTE nzl = *p++;						// 油枪号
	uint32_t price = *((uint16*)p);			// 单价

	TNZLOILINFO ifo;
	ifo.ChlNo = chn;
	ifo.NZL = nzl;

	for(int i=0; i<NZLCNT; i++)
	{
		TNZLOILDATA &r = NzlDat[i];
		if((r.ChlNo == chn) && (r.NZL == nzl))
		{
			r.Oil1.Price = price;
			ifo.OilCode = r.Oil1.OilCode;
			ifo.Price = price;
			ifo.Density = r.Oil1.Density;

			if(NotifyEvent) NotifyEvent(MDCNo, 105, (BYTE*)&ifo, sizeof(TNZLOILINFO));
			break;
		}
	}
}
//---------------------------------------------------------------------------

//上传通道最大TTC信息
void TMDC::UL_ChlMaxTTC(BYTE *pData)
{
	BYTE *p = pData;
	TMDCTTC ttc;
	ttc.ChlNo =*p++;						// 通道号
	ttc.TTC = *((uint32*)p);				// TTC

	if(NotifyEvent) NotifyEvent(MDCNo, 110, (BYTE*)&ttc, sizeof(TMDCTTC));
}
//---------------------------------------------------------------------------

//上传上位机设置授权时段
void TMDC::UL_QryAuthCfg(BYTE *pData)
{
	BYTE *p = pData;
	TAUTHCFG cfg;
	memset(&cfg, 0, sizeof(TAUTHCFG));
	cfg.Num = *((int*)p);
	p += sizeof(int);
	for(int i=0; i<cfg.Num; i++)
	{
		TPICETIME &t = cfg.Items[i];
		t.tm0.Hour = *p++;
		t.tm0.Min = *p++;
		t.tm0.Sec = *p++;
		t.tm1.Hour = *p++;
		t.tm1.Min = *p++;
		t.tm1.Sec = *p++;
	}

	if(NotifyEvent) NotifyEvent(MDCNo, 111, (BYTE*)&cfg, sizeof(TAUTHCFG));
}
//---------------------------------------------------------------------------

//向上位机查询授权
void TMDC::UL_QryAuth(BYTE *pData)
{
	BYTE *p = pData;
	TNZLADDR adr;
	adr.ChlNo = *p++;						// 通道号
	adr.NZL = *p;							// NZN

	if(NotifyEvent) NotifyEvent(MDCNo, 112, (BYTE*)&adr, sizeof(TNZLADDR));
}
//---------------------------------------------------------------------------

//枪授权结果
void TMDC::UL_AuthRet(BYTE *pData)
{
	BYTE *p = pData;
	TAUTHRESULT rt;
	rt.ChlNo = *p++;						// 通道号
	rt.NZL = *p++;							// 枪号
	rt.Result = *p;							// 授权结果

	if(NotifyEvent) NotifyEvent(MDCNo, 113, (BYTE*)&rt, sizeof(TAUTHRESULT));
}
//---------------------------------------------------------------------------

//枪取消授权结果
void TMDC::UL_CancelAuthRet(BYTE *pData)
{
	BYTE *p = pData;
	TAUTHRESULT rt;
	rt.ChlNo = *p++;						// 通道号
	rt.NZL = *p++;							// 枪号
	rt.Result = *p;							// 取消授权结果

	if(NotifyEvent) NotifyEvent(MDCNo, 114, (BYTE*)&rt, sizeof(TAUTHRESULT));
}
//---------------------------------------------------------------------------

//上传集线器硬件信息，pData为指向TDEVINFO
void TMDC::UL_DevInfo(BYTE *pData)
{
	TDEVINFO *pInfo = (TDEVINFO*)pData;
	TDEVINFO rt = *pInfo;
	if(NotifyEvent) NotifyEvent(MDCNo, 115, (BYTE*)&rt, sizeof(TDEVINFO));
}
//---------------------------------------------------------------------------

TClientSocket::TClientSocket(TMDC *pMDC) : FSocket(-1),
	MDC(pMDC), SendTimeout(2000), RecvTimeout(3000)
{
}
//---------------------------------------------------------------------------

TClientSocket::~TClientSocket()
{
	CloseSocket();
}
//---------------------------------------------------------------------------

//返回值：
//  0:表示超时
// -1:socket出错
//  1：读取1Byte数据
int TClientSocket::ReadByte(char *ch)
{
	struct timeval tv;
	fd_set rd_set;
	FD_ZERO(&rd_set);
	FD_SET(FSocket, &rd_set);
	tv.tv_sec = RecvTimeout / 1000;
	tv.tv_usec = (RecvTimeout % 1000) * 1000;

	int rt = select(FSocket + 1, &rd_set, NULL, NULL, &tv);
	if(rt > 0)
	{
		rt = recv(FSocket, ch, 1, 0);
		if(rt == 0) rt = -1;			//接收到数据的长度为0，表示对方关闭套接字
	}
	return rt;
}
//---------------------------------------------------------------------------

//0: 成功, 1: 已创建, -1: 失败
int TClientSocket::CreateSocket()
{
	if(FSocket < 0)
	{
		FSocket = socket(AF_INET, SOCK_STREAM, 0);
		if(FSocket < 0)
		{
			LogOut("Error: CreateSocket failed.");
			return -1;
		}

		//set socket recv/send timeout
		struct timeval tv;

		//设置发送超时
		tv.tv_sec = SendTimeout / 1000;
		tv.tv_usec = (SendTimeout % 1000) * 1000;
		setsockopt(FSocket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));

		//设置接收超时
		tv.tv_sec = RecvTimeout / 1000;
		tv.tv_usec = (RecvTimeout % 1000) * 1000;
		setsockopt(FSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv));
		return 0;
	}
	return 1;
}
//---------------------------------------------------------------------------

// 0:成功, -1:失败
int TClientSocket::ConnectTo(char *pzIP, uint16 port)
{
	struct sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr(pzIP);

	int error = -1, len = sizeof(int);
	timeval tm;
	fd_set set;
	unsigned long ul = 1;
	ioctl(FSocket, FIONBIO, &ul); 			// 设置为非阻塞模式
	bool ret = false;
	if (connect(FSocket, (struct sockaddr *)&addr, sizeof(addr)) == -1)
	{
		tm.tv_sec = RecvTimeout / 1000;
		tm.tv_usec = (RecvTimeout % 1000) * 1000;
		FD_ZERO(&set);
		FD_SET(FSocket, &set);
		if (select(FSocket + 1, NULL, &set, NULL, &tm) > 0)
		{
			getsockopt(FSocket, SOL_SOCKET, SO_ERROR, &error, (socklen_t*)&len);
			if (error == 0) ret = true;
		}
	}
	else ret = true;

	ul = 0;
	ioctl(FSocket, FIONBIO, &ul);			// 设置为阻塞模式
	if (!ret)
	{
		close(FSocket);
		fprintf(stderr, "Error: Cannot Connect to server.");
		return -1;
	}

	int sta = 1;
	if(MDC->NotifyEvent)
		MDC->NotifyEvent(MDC->MDCNo, 101, (BYTE*)&sta, sizeof(int));

	return 0;
}
//---------------------------------------------------------------------------

void TClientSocket::CloseSocket()
{
	if(FSocket != -1)
	{
		close(FSocket);
		FSocket = -1;
		int sta = 0;
		if(MDC->NotifyEvent)
			MDC->NotifyEvent(MDC->MDCNo, 101, (BYTE*)&sta, sizeof(int));
	}
}
//---------------------------------------------------------------------------

int TClientSocket::SendBuffer(char *pBuffer, int iSize)
{
	char *p = pBuffer;
	int remain = iSize;
	TTimerEx timer;
	timer.Begin();

	while(remain > 0)
	{
		if(!MDC->Working) return 0;
		int s = send(FSocket, p, remain, 0);
		if(s > 0)
		{
			remain -= s;
			p += s;
		}
		else if (s < 0)
		{
			LogOut("socket write error!");
			return -1;
		}

		int ms = timer.Elapsed();
		if(ms > SendTimeout)
		{
			LogOut("Error: send timeout.");
			return -1;
		}
	}
	return iSize;
}
//---------------------------------------------------------------------------

//返回值： -1：socket出错，>0：读到的数据长度
int TClientSocket::RecvBuffer(char *pBuffer, int iSize)
{
	char *p = pBuffer;
	bool bhdr = false;
	int rd = 0;
	TTimerEx timer;
	timer.Begin();

	while(rd < iSize)
	{
		if(!MDC->Working) return 0;
		if(FSocket < 0) break;

		int r = ReadByte(p);
		if(r == 0)
		{
			int ms = timer.Elapsed();
			if(ms > 60500)
			{
				LogOut("Error: The time over 60 seconds no data.");
				return -1;
			}
			continue;
		}

		if(r < 0)
		{
			LogOut("socket read error!");
			return -1;
		}

		switch(*p)
		{
			case FRMHDR:
			if(!bhdr)
			{
				bhdr = true;
				p++;
			}
			else
			{
				pBuffer[0] = *p;
				p = pBuffer + 1;
			}
			rd = 1;
			break;

			case FRMTAIL:
			if(bhdr)
			{
				rd++;
				return rd;
			}
			else
			{
				p = pBuffer;
				rd = 0;
			}
			break;

			default:
			p++;
			rd++;
			break;
		}
	}

	return -1;					//缓冲区满，未收到正常数据包
}
//---------------------------------------------------------------------------

TSendThread::TSendThread(TMDC *pMdc) : MDC(pMdc), IsOver(false)
{
	Working = true;
}
//---------------------------------------------------------------------------

void TSendThread::Execute()
{
	TTimerEx timer;
	while (!Working && !IsExit) sleep(10);
	timer.Begin();
	ReadWatch = false;

	while(MDC->Working)
	{
		TSNDCMDLST &cmds = MDC->CmdLst;
		if(cmds.size() > 0)
		{
			TSNDCMDLST lst;
			lst.swap(cmds);
			int cnt = lst.size();

			for(int i=0; i<cnt; i++)
			{
				if(!MDC->Working) break;
				TFRAMEBIN *frm = lst.at(i);
				MDC->SendCmd(frm);
			}

			//释放空间
			for(int i=0; i<cnt; i++)
			{
				TFRAMEBIN *frm = lst.at(i);
				delete frm;
			}
		}

		SleepEx(10);
		if(ReadWatch)
		{
			ReadWatch = false;
			timer.Begin();
		}
		else
		{
			uint32 ms = timer.Elapsed();
			if(ms >= 60500)
			{
				LogOut("Error: No data received for more than 60 seconds, Close socket.");
				MDC->CltSock->CloseSocket();
				SleepEx(500);
				MDC->Connect();
				timer.Begin();
			}
		}
	}

	IsOver = true;
	LogOut("SendThread exit.");
}
//---------------------------------------------------------------------------

TRecvThread::TRecvThread(TMDC *pMdc) : MDC(pMdc), IsOver(false)
{
	Working = true;
}
//---------------------------------------------------------------------------

void TRecvThread::Execute()
{
	while (!Working && !IsExit) sleep(10);
	while(MDC->Working)
	{
		Active = 1;
		try
		{
			MDC->ReadFrame();
		}
		catch(...) { }
		SleepEx(10);
	}

	IsOver = true;
	LogOut("RecvThread exit.");
}
//---------------------------------------------------------------------------


